class IndexedDBQuery {

    //判断浏览器是否支持IndexedDB
    static idbOk() {
        return 'indexedDB' in window;
    }

    constructor(databaseName, version = 1) {

        //初始化IndexedDB为null
        this.db = null;

        //开启IndexedDB请求
        this.openRequest = indexedDB.open(databaseName, version);

    }

    //初始化IndexedDB数据库请求时间状态监听
    initOpenRequestEvent() {
        let openRequest = this.openRequest;
        return new Promise((resolve, reject) => {
            openRequest.addEventListener('error', ev => {
                resolve({
                    state: 'error',
                    result: openRequest.error,
                });
            });
            openRequest.addEventListener('success', ev => {
                this.db = openRequest.result;
                resolve({
                    state: 'success',
                    result: openRequest.result
                });
            });
            openRequest.addEventListener('upgradeneeded', ev => {
                this.db = openRequest.result;
                resolve({
                    state: 'upgraded',
                    result: openRequest.result
                });
            });
        });
    }

    //创建一个对象仓库（一张表格）并初始化创建索引键名
    create(objectStoreName, keyNames, config) {

        let db = this.db;
        if (db.objectStoreNames.contains(objectStoreName)) return;
        let objStore = db.createObjectStore(objectStoreName, config.store);
        keyNames.forEach(key => objStore.createIndex(key, key, config.index));

    }

    //给指定对象仓库（表）中，添加一条数据
    add(objectStoreName, config) {

        let transaction = this.db.transaction([objectStoreName], config.mode),
            objStore = transaction.objectStore(objectStoreName),
            request = objStore.add(config.data);

        return new Promise((resolve, reject) => {
            request.addEventListener('success', ev => resolve(request));
            request.addEventListener('error', ev => reject(ev.target.error));
        });

    }

    //移除指定对象仓库中的所有数据
    removeAll() {
        let transaction = this.db.transaction([objectStoreName], config.mode),
            objStore = transaction.objectStore(objectStoreName);
        objStore.clear();
    }

    //移除指定对象仓库中的某条数据（以主键名为删除参数）
    remove(objectStoreName, config) {

        let transaction = this.db.transaction([objectStoreName], config.mode),
            objStore = transaction.objectStore(objectStoreName),
            request = objStore.delete(config.indexKey);

        return new Promise((resolve, reject) => {
            request.addEventListener('success', ev => resolve(request));
        });

    }

    //修改指定对象仓库中的某条数据
    modify(objectStoreName, config) {

        let transaction = this.db.transaction([objectStoreName], config.mode),
            objStore = transaction.objectStore(objectStoreName),
            request = objStore.put(config.data);

        return new Promise((resolve, reject) => {
            request.addEventListener('success', ev => resolve(request));
            request.addEventListener('error', ev => reject(ev.target.error));
        });


    }

    // 读取指定对象仓库中的某条数据
    read(objectStoreName, config) {

        let transaction = this.db.transaction([objectStoreName], config.mode),
            objStore = transaction.objectStore(objectStoreName),
            request = objStore.get(config.indexKey);

        return new Promise((resolve, reject) => {
            request.addEventListener('success', ev => resolve(request.result));
            request.addEventListener('error', ev => reject(ev.target.error));
        });

    }

    //读取指定对象仓库的所有数据
    readAll(objectStoreName) {

        let objStore = this.db.transaction(objectStoreName).objectStore(objectStoreName);

        return new Promise((resolve, reject) => {
            let resArr = [];
            objStore.openCursor().addEventListener('success', ev => {
                let curItem = ev.target.result;
                //如果不是最后一项
                if (curItem !== null) {
                    resArr.push(curItem.value);
                    curItem.continue(); //开启下一条数据读取，否则只会读第一跳
                    //如果是最后一项就resolve结果
                } else {
                    resolve(resArr);
                }
            });
        });

    }

}

//输入框类
class InfoInput {

    constructor(el) {
        this.el = el;
        this.value = '';
        this.init();
    }

    init() {
        this.change();
    }

    change() {
        this.el.addEventListener('change', ev => {
            this.value = this.el.value;
        });
    }

}


//存储数据的键名集合
let keyNames = [
    'name',
    'age',
    'hobby',
    'id',
];

//# init person informations

let personIDB = new IndexedDBQuery('person');

//连接数据库后需要执行的不同状态方法
let connectDBAfter = {
    //数据库版本升级或初次创建数据库后
    upgraded() {
        personIDB.create('relativeInfo', keyNames, {
            store: {
                autoIncrement: true
                // keyPath: 'id'
            },
            index: {
                unique: false
            }
        });
    },
    //连接数据库成功后
    success() {
        personIDB.readAll('relativeInfo').then(res => {
            res.forEach(item => {
                renderTableRow(Object.values(item));
            });
        });
    },
    //连接数据库失败后
    error(params) {
        console.info('error');
    }
}

//连接IndexedDB数据库后，根据连接状态执行对应方法
personIDB.initOpenRequestEvent().then(res => {
    let state = res.state; //获取连接状态
    connectDBAfter[state](); //执行对应的函数
});

//table表格部分
let table = document.querySelector('.table'),
    writeArea = document.querySelector('.write-infos'),
    submitInfosBtn = writeArea.querySelector('.submit-infos');
let inputEles = [
        'name-input',
        'age-input',
        'hobby-input',
        'id-input',
    ].map(val => writeArea.querySelector(`.${val}`)),
    inputEleInstances = inputEles.map(el => new InfoInput(el));

//渲染表格（一次渲染一行）
function renderTableRow(values) {
    let ul = document.createElement('ul');
    ul.className = 'row';
    ul.innerHTML = values.map(value => `<li class='row-item'>${value}</li>`).join('');
    table.append(ul);
}

//生成数据按钮点击监听
submitInfosBtn.addEventListener('click', ev => {
    let values = inputEleInstances.map(ins => ins.value),
        hasValue = values.every(value => value !== '');
    //如果数据是完整的
    if (hasValue) {
        renderTableRow(values); //渲染数据表格
        //添加数据到数据库
        personIDB.add('relativeInfo', {
            mode: 'readwrite',
            data: keyNames.reduce((total, now, i) => {
                total[now] = values[i];
                return total;
            }, {}),
        });
    }
});